package com.totoro.rabbitmq.consumer;

import com.totoro.rabbitmq.RabbitMQConstant;
import org.springframework.amqp.core.*;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.HashMap;
import java.util.Map;

/**
 * 客户端的RabbitMQ的消息绑定
 * 主要配置exchange与queue的绑定，以及消息监听的配置
 * Created by Administrator on 2017/9/15.
 */
@Configuration
public class ConsumerBinding {
    //exchange

    /**
     * fanout类型的Exchange
     * exchange名称要对应相同的exchange类型，否则报错！
     * @return
     */
    @Bean
    public FanoutExchange fanoutExchange(){
        //exchange名称，exchange内消息是否持久化，是否自动删除消息
        return new FanoutExchange(RabbitMQConstant.exchange.EXCHANGE_FANOUT_AMQ) ;
    }

    /**
     * direct类型Exchange
     * @return
     */
    @Bean
    public DirectExchange directExchange(){
        return new DirectExchange(RabbitMQConstant.exchange.EXCHANGE_DIRECT_AMQ) ;
    }

    /**
     * topic类型的Exchange
     * @return
     */
    @Bean
    public TopicExchange topicExchange(){
        return new TopicExchange(RabbitMQConstant.exchange.EXCHANGE_TOPIC_AMQ) ;
    }

    /**
     * headers类型的Exchange
     * @return
     */
    @Bean
    public HeadersExchange headersExchange(){
        return new HeadersExchange(RabbitMQConstant.exchange.EXCHANGE_HEADERS_AMQ) ;
    }

    /**
     * Queue
     * Queue创建时的四个属性name， durable， exclusive， auto-delete
     * name:queue的名字用来标识一个队列
     * durable：持久化。队列会保存到磁盘，当RabbitMQ broker重启时，会从磁盘恢复队列。（在broker重启期间，仅会恢复queue中的消息）
     * exclusive：独占性，exclusive队列只能通过其声明连接来使用，当其声明connection断开，则queue删除
     * auto-delete：自动删除：是否当最后一个消息消费者断开connection后自动删除队列
     *
     durable属性和auto-delete属性可以同时生效；
     durable属性和exclusive属性会有性质上的冲突，两者同时设置时，仅exclusive属性生效；当设置durable为false时，exclusive设置true，durable=false无意义
     auto_delete属性和exclusive属性可以同时生效


     Queue的“Exlusive owner”对应的是connection而不是channel；
     Consumer存在于某个channel上的；

     */

    @Bean(name = "queue_hello")
    public Queue queueHello(){
        return new Queue(RabbitMQConstant.queue.QUEUE, true, false, false);
    }

    @Bean(name="queue_add")
    public Queue queueAdd(){
        return new Queue(RabbitMQConstant.queue.QUEUE_ADD) ;
    }

    //绑定配置
    /**
     * fanout类型的Exchange路由到hello这个Queue上
     * 类似于一种广播的机制，只要注册到这个exchange上的队列，都可以接受到发送到该exchange的消息
     */
    @Bean
    public Binding exchange_fanout_hello(FanoutExchange fanoutExchange,  @Qualifier("queue_hello") Queue queue){
        return BindingBuilder.bind(queue).to(fanoutExchange) ;
    }

    @Bean
    public Binding exchange_fanout_add(FanoutExchange fanoutExchange, @Qualifier("queue_add") Queue queue){
        return BindingBuilder.bind(queue).to(fanoutExchange) ;
    }

    /**
     * direct类型的Exchange路由到hello上并且Routing Key为：exchange_direct_hello
     * 只有注册到该exchange，并且注册时的路由key与消息的路由key匹配的queue，才能接收到该exchange上的消息
     * @param directExchange
     * @param queue
     * @return
     */
    @Bean
    public Binding exchange_direct_hello(DirectExchange directExchange, @Qualifier("queue_hello") Queue queue){
        return BindingBuilder.bind(queue).to(directExchange).with("exchange_direct_hello") ;
    }

    /**
     * direct类型的exchange路由到add上并且Routing Key为：exchange_direct_add
     * @param directExchange
     * @param queue
     * @return
     */
    @Bean
    public Binding exchange_direct_add(DirectExchange directExchange, @Qualifier("queue_add") Queue queue){
        return BindingBuilder.bind(queue).to(directExchange).with("exchange_direct_add") ;
    }

    /**
     * topic类型的exchange路由到hello上并且Routing Key为：exchange_topic_hello_1
     * @param topicExchange
     * @param queue
     * @return
     */
    @Bean Binding exchange_topic_hello_1(TopicExchange topicExchange, @Qualifier("queue_hello") Queue queue){
        return BindingBuilder.bind(queue).to(topicExchange).with("exchange.topic.hello.1") ;
    }

    /**
     * topic类型的exchange路由到hello上并且Routing Key为：exchange_topic_hello_2
     * @param topicExchange
     * @param queue
     * @return
     */
    @Bean Binding exchange_topic_hello_2(TopicExchange topicExchange, @Qualifier("queue_hello") Queue queue){
        return BindingBuilder.bind(queue).to(topicExchange).with("exchange.topic.hello.2") ;
    }

    /**
     * topic类型的Exchange路由到hello上，并且路由key为模糊匹配 模糊匹配的key为：topic_#
     * Routing Key为一个句点号“.”分隔的字符串（我们将被句点号". "分隔开的每一段独立的字符串称为一个单词），如"stock.usd.nyse"、"nyse.vmw"、"quick.orange.rabbit"。Binding Key与Routing Key一样也是句点号“. ”分隔的字符串。
     Binding Key中可以存在两种特殊字符"*"与"#"，用于做模糊匹配，其中"*"用于匹配一个单词，"#"用于匹配多个单词（可以是零个）
     * @param topicExchange
     * @param queue
     * @return
     */
    @Bean Binding exchange_topic_all(TopicExchange topicExchange, @Qualifier("queue_add") Queue queue){
        return BindingBuilder.bind(queue).to(topicExchange).with("exchange.topic.#") ;
    }

    /**
     * headers类型的Exchange路由到hello上，这个通过header中的参数来匹配
     * @param headersExchange
     * @param queue
     * @return
     */
    @Bean Binding exchange_headers_hello(HeadersExchange headersExchange, @Qualifier("queue_hello") Queue queue){
        return BindingBuilder.bind(queue).to(headersExchange).where("to").matches("Niki") ;
    }

    /**
     * headers类型的Exchange路由到hello上，这个通过header中的参数来匹配
     * @param headersExchange
     * @param queue
     * @return
     */
    @Bean Binding exchange_headers_add(HeadersExchange headersExchange, @Qualifier("queue_add") Queue queue){
        Map<String,Object> headers = new HashMap<String,Object>() ;
        headers.put("to","Niki") ;
        headers.put("opt","add") ;
        return BindingBuilder.bind(queue).to(headersExchange).whereAll(headers).match() ;
    }

    @Bean
    public Queue patchQueue() {
        return new Queue("EAS:PATCH:SERVICE:QUEUEB");
    }
    @Bean
    public FanoutExchange patchExchange() {
        return new FanoutExchange("EAS:PATCH:SERVICE:EXCHANGE");
    }
    @Bean
    public Binding patchBinding(Queue patchQueue, FanoutExchange patchExchange) {
        return BindingBuilder.bind(patchQueue).to(patchExchange);
    }

}
